﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Repetition.Persistence;
using Repetition.Domain;
using Bule.Components.FilteredSelectionList;
using Repetition.Views.Controls;
//using Repetition.Persistence.NHibernate;
using Repetition.Persistence.FluentNHibernate;
using System.Drawing;
using Repetition.Conversion;
using Bule.Components.InputBox;
using Repetition.Utilities.Conversion;

namespace Repetition.Views
{
    public partial class MainView : Form
    {
        // Controls
        private TypedListView<Subject> subjectListView = new TypedListView<Subject>(x => x.Name);
        private TypedListView<Problem> problemListView = new TypedListView<Problem>(x => x.Question);
        private ProblemDifficultyImportanceView difficultyImportanceView;

        // Model members
        private IProblemList problems;
        private ISubjectList subjects;
        private Problem selectedProblem = null;
        IListFactory listFactory = new Repetition.Persistence.FluentNHibernate.PersistentListFactory();

        // View state members
        private Subject rightClickedSubject;
        private Problem rightClickedProblem;

        public MainView()
        {
            problems = listFactory.CreateProblemList();
            subjects = listFactory.CreateSubjectList();

            InitializeComponent();

            problemListView.MultiSelect = false;
            problemListView.Dock = DockStyle.Fill;
            problemListView.View = View.List;
            problemListView.HideSelection = false;
            problemListView.ItemActivate += new EventHandler(problemListView_ItemActivate);
            problemListView.MouseDown += new MouseEventHandler(problemListView_MouseDown);

            subjectListView.MultiSelect = true;
            subjectListView.Dock = DockStyle.Fill;
            subjectListView.View = View.List;
            subjectListView.HideSelection = false;
            subjectListView.ItemSelectionChanged += new ListViewItemSelectionChangedEventHandler(subjectList_ItemSelectionChanged);
            subjectListView.MouseDown += new MouseEventHandler(subjectListView_MouseDown);

            problemsGroupBox.Controls.Add(problemListView);
            subjectsGroupBox.Controls.Add(subjectListView);

            difficultyImportanceView = new ProblemDifficultyImportanceView(ProblemDifficultyOrImportanceChangedEvent);
            difficultyImportanceView.Dock = DockStyle.Fill;
            
            problemPropertyLayoutPanel.Controls.Add(difficultyImportanceView, 1, 0);
        }

        void problemListView_MouseDown(object sender, MouseEventArgs e)
        {
            ListViewItem item = problemListView.GetItemAt(e.X, e.Y);

            if (item != null && e.Button == MouseButtons.Right)
            {
                problemContextMenu.Show((ListView)sender, new Point(e.X, e.Y));
                rightClickedProblem = (Problem)item.Tag;
            }
        }

        void subjectListView_MouseDown(object sender, MouseEventArgs e)
        {
            ListViewItem item = subjectListView.GetItemAt(e.X, e.Y);

            if (item != null && e.Button == MouseButtons.Right)
            {
                subjectContextMenu.Show((ListView)sender, new Point(e.X, e.Y));
                rightClickedSubject = (Subject)item.Tag;
            }
        }

        private void MainView_Load(object sender, EventArgs e)
        {
            LoadSubjects();
        }

        private void subjectList_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            LoadProblemsWithSelectedSubjects();
        }

        private void showAnswerButton_Click(object sender, EventArgs e)
        {
            ShowAnswer(selectedProblem);
        }

        private void nextButton_Click(object sender, EventArgs e)
        {
            LoadNextProblem();
        }

        private void previousButton_Click(object sender, EventArgs e)
        {
            LoadPreviousProblem();
        }

        private void quitToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void addProblemToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddNewProblem();
        }

        private void addSubjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddNewSubject();
        }

        private void editProblemToolStripMenuItem_Click(object sender, EventArgs e)
        {
            EditProblem(selectedProblem);
        }

        private void ProblemDifficultyOrImportanceChangedEvent()
        {
            problems.SaveChanges(selectedProblem);
        }


        private void importToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ImportFromXml();
        }

        private void toHTMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ExportToHtml();
        }

        private void subjectEditToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (rightClickedSubject != null)
            {
                EditSubject(rightClickedSubject);
                rightClickedSubject = null;
            }
        }

        private void subjectRemoveToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (rightClickedSubject != null)
            {
                RemoveSubject(rightClickedSubject);
                rightClickedSubject = null;
            }
        }

        private void problemEditToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (rightClickedProblem != null)
            {
                EditProblem(rightClickedProblem);
                rightClickedProblem = null;
            }
        }

        private void problemRemoveToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (rightClickedProblem != null)
            {
                RemoveProblem(rightClickedProblem);
                rightClickedProblem = null;
            }
        }

        private void problemListView_ItemActivate(object sender, EventArgs e)
        {
            selectedProblem = problemListView.SelectedItem;
            UpdateFormFromProblem(selectedProblem);
        }

        private void addToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AddNewProblem();
        }

        private void removeProblemToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RemoveProblem(selectedProblem);
        }

        private void removeSubjectToolStripMenuItem_Click(object sender, EventArgs e)
        {
            RemoveSelectedSubjects();
        }

        private void toXMLToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ExportToXml();
        }

        private void ExportToXml()
        {
            saveFileDialog.Filter = "XML files (*.xml)|*.html|All files (*.*)|*.*";
            DialogResult result = saveFileDialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                using (IProblemList completeProblemList = listFactory.CreateProblemList())
                {
                    completeProblemList.Load(subjects.GetAll());
                    XmlConverter.Export(subjects.GetAll(), completeProblemList.GetAll(), saveFileDialog.FileName);
                }
            }
        }

        private void ImportFromXml()
        {
            DialogResult result = openFileDialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                ICollection<Subject> importedSubjects;
                ICollection<Problem> importedProblems;

                XmlConverter.Import(openFileDialog.FileName, out importedSubjects, out importedProblems);

                // subjects.Clear();
                // problems.Clear();

                foreach (var subject in importedSubjects)
                    subjects.Add(subject);

                foreach (var problem in importedProblems)
                    problems.Add(problem);

                LoadSubjects();
                LoadProblemsWithSelectedSubjects();
            }
        }

        private void ExportToHtml()
        {
            saveFileDialog.Filter = "HTML files (*.html)|*.html|All files (*.*)|*.*";

            DialogResult result = saveFileDialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                using (IProblemList completeProblemList = listFactory.CreateProblemList())
                {
                    completeProblemList.Load(subjects.GetAll());
                    HtmlExporter.ExportToFile(saveFileDialog.FileName, completeProblemList.GetAll());
                }
            }
        }

        private void LoadProblemsWithSelectedSubjects()
        {
            var selectedSubjects = subjectListView.SelectedItems;
            problems.Load(selectedSubjects);
            problemListView.Add(problems.GetAll(), true);

            if (problems.Count > 0)
                selectedProblem = problems.Get(0);
        }

        private void LoadNextProblem()
        {
            selectedProblem = problems.GetNext(selectedProblem);
            UpdateFormFromProblem(selectedProblem);
        }

        private void LoadPreviousProblem()
        {
            selectedProblem = problems.GetPrevious(selectedProblem);
            UpdateFormFromProblem(selectedProblem);
        }

        private void UpdateFormFromProblem(Problem problem)
        {
            questionTextbox.Text = "";
            answerTextbox.Text = "";

            if (problems != null)
            {
                nextButton.Enabled = problems.HasNext(problem);
                previousButton.Enabled = problems.HasPrevious(problem);
            
                UpdateProblemListViewSelectedProblem(problem);

                questionTextbox.Text = problem.Question;

                difficultyImportanceView.Problem = problem;
            }
        }

        private void ShowAnswer(Problem problem)
        {
            answerTextbox.Text = problem.Answer;
        }

        private void UpdateProblemListViewSelectedProblem(Problem problem)
        {
            problemListView.BeginUpdate();
            problemListView.SelectedIndices.Clear();

            problemListView.SelectItem(problem);

            problemListView.EndUpdate();
        }

        private void AddNewProblem()
        {
            var addProblemDialog = new AddProblemDialog(subjects.GetAll());
            DialogResult result = addProblemDialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                // save
                var problem = addProblemDialog.Problem;
                problems.Add(problem);
                problemListView.Add(problem);
            }
        }

        private void EditProblem(Problem problem)
        {
            var addProblemDialog = new AddProblemDialog(subjects.GetAll(), problem);
            DialogResult result = addProblemDialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                problem.Copy(addProblemDialog.Problem);
                problems.SaveChanges(problem);
                problemListView.RefreshTitles();
                UpdateFormFromProblem(selectedProblem);
            }
        }

        private void AddNewSubject()
        {
            var addSubjectDialog = new AddSubjectDialog();

            DialogResult result = addSubjectDialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                subjects.Add(addSubjectDialog.Subject);

                LoadSubjects();
            }
        }

        private void LoadSubjects()
        {
            // Load all subjects, and add them to the list:
            subjects.Load();
            subjectListView.Add(subjects.GetAll(), true);
        }

        private void RemoveProblem(Problem problem)
        {
            problems.Remove(problem);
            
            if (problem == selectedProblem)
                selectedProblem = null;

            LoadProblemsWithSelectedSubjects();
            UpdateFormFromProblem(selectedProblem);
        }
        
        private void RemoveSelectedSubjects()
        {
            var selectedSubjects = subjectListView.SelectedItems;

            var result = MessageBox.Show("Do you really want to remove the selected subjects?",
                "Remove Subjects?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);

            if (result == DialogResult.Yes)
            {

                foreach (var subject in selectedSubjects)
                {
                    subjects.Remove(subject);
                    subjectListView.Remove(subject);
                }
            }
        }

        private void RemoveSubjectFromListView(Subject subject)
        {
            subjectListView.Remove(subject);
        }

        private void EditSubject(Subject subject)
        {
            var addSubjectDialog = new AddSubjectDialog(subject);

            DialogResult result = addSubjectDialog.ShowDialog();

            if (result == DialogResult.OK)
            {
                subject.Copy(addSubjectDialog.Subject);

                subjectListView.RefreshTitles();
            }
        }

        private void RemoveSubject(Subject subject)
        {
            subjects.Remove(subject);
            RemoveSubjectFromListView(subject);
        }
    }
}